/** Shift
 */

#include "data.h"

module ShiftP {
	provides interface Shift;
}

implementation {
	
	DataEntry table_last_received[NUMBER_OF_NODES];
	DataEntry table_shifts[NUMBER_OF_NODES][NUMBER_OF_NODES];
	
	bool valid[NUMBER_OF_NODES];
	
	bool learning = TRUE;
	
	command void Shift.set(DataEntry *entry, uint8_t NodeId) {
		uint8_t i;
		uint8_t diff;
		
		if(learning) {
			/* if we are learning update the maximum difference seen
			 * for each value.
			 */
			
			for( i = 0; i < NUMBER_OF_NODES; ++i) { 
				diff = abs(entry->humidity - table_last_received[i].humidity);
				if( diff > table_shifts[NodeId][i].humidity) {
					table_shifts[NodeId][i].humidity = diff;
					table_shifts[i][NodeId].humidity = diff;
				}
				diff = abs(entry->temperature - table_last_received[i].temperature);
				if( diff > table_shifts[NodeId][i].temperature) {
					table_shifts[NodeId][i].temperature = diff;
					table_shifts[i][NodeId].temperature = diff;
				}
				diff = abs(entry->lightPar - table_last_received[i].lightPar);
				if( diff > table_shifts[NodeId][i].lightPar) {
					table_shifts[NodeId][i].lightPar = diff;
					table_shifts[i][NodeId].lightPar = diff;
				}
				diff = abs(entry->lightTsr - table_last_received[i].lightTsr);
				if( diff > table_shifts[NodeId][i].lightTsr) {
					table_shifts[NodeId][i].lightTsr = diff;
					table_shifts[i][NodeId].lightTsr = diff;
				}
			}
			
			valid[NodeId] = TRUE;
			
		} else {
			/* Not learning anymore. Check if sample is beneath
			 * expected maximum variation, if not mark node as not valid.
			 */
			i = TOS_NODE_ID;
         
			if (abs(entry->humidity - table_last_received[i].humidity) > table_shifts[NodeId][i].humidity || 
				abs(entry->temperature - table_last_received[i].temperature) > table_shifts[NodeId][i].temperature ||
				abs(entry->lightPar - table_last_received[i].lightPar) > table_shifts[NodeId][i].lightPar ||
				abs(entry->lightTsr - table_last_received[i].lightTsr) > table_shifts[NodeId][i].lightTsr ) {
				
				valid[NodeId] = FALSE;
			} else {
				valid[NodeId] = TRUE;
			}
		}
		
		// save last entry
		table_last_received[NodeId] = *entry;
	}
	
	command void Shift.set_msg(DataMessage *msg) {
		DataEntry e;
		data_msg2entry(msg, &e);
		call Shift.set(&e, msg->source);
	}
	
	/** Set learning flag.
	 * \param l true to activate learning, false to stop.
	 */
	command void Shift.set_learning(bool l) {
		learning = l;
	}
	
	/** Check if node is considered valid. */
	command bool Shift.is_valid(uint8_t NodeId) {
		return valid[NodeId];
	}
	
	command uint32_t Shift.get_new_time(uint8_t NodeId, DataEntry *mean){
		DataEntry* last_entry;
		uint16_t d1, d2, diff;
		uint32_t newtime;
		
		// compute slope of the light curve
		last_entry = &table_last_received[NodeId];
		d1 = abs(mean->lightPar - last_entry->lightPar);
		d2 = abs(mean->lightTsr - last_entry->lightTsr);
		diff = d1 > d2 ? ((float)d1) : ((float)d2);
		printf("diff %u ", diff);
		
		// adapt step size
		if(diff > THR_LIGHT) {
			
			newtime = STEP_MIN;
			
		} else {
		
			newtime = STEP_MAX;
			
		}
		
		return newtime;
  
	}
	
}